package com.guavamail.smtp.command.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;

import org.apache.mina.core.session.IoSession;

import com.guavamail.smtp.SMTPContext;
import com.guavamail.smtp.SessionStatus;
import com.guavamail.smtp.command.AbstractCommand;
import com.guavamail.smtp.exception.MessageSizeException;
import com.guavamail.smtp.mailer.DSNStatus;
import com.guavamail.smtp.mailer.MailHeaders;
import com.guavamail.smtp.mailer.RFC2822Headers;
import com.guavamail.smtp.mailer.dates.RFC822DateFormat;
import com.guavamail.smtp.stream.SharedStreamUtils;
import com.guavamail.smtp.stream.SizeLimitedInputStream;

public class DATA extends AbstractCommand {
	public DATA() {
		super("DATA", "");
	}

	/**
	 * Static RFC822DateFormat used to generate date headers
	 */
	private final static RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();

	@Override
	public void execute(String commandString, IoSession ioSession, SMTPContext ctx) throws IOException {
		SessionStatus sessionStatus = ctx.getSessionStatus();
		if (!sessionStatus.getHasSender()) {
			sendResponse(ioSession, "503 Error: need MAIL command");
			return;
		} else if (sessionStatus.getRecipientCount() == 0) {
			sendResponse(ioSession, "503 Error: need RCPT command");
			return;
		}
		if (ctx.getInputStream() == null) {// start
			sessionStatus.setDataMode(true);
			sendResponse(ioSession, "354 End data with <CR><LF>.<CR><LF>");
		} else {// end
			try {

				InputStream msgIn = SharedStreamUtils.getPrivateInputStream(false, ctx.getInputStream());
				long maxMessageSize = ctx.getSMTPServerConfig().getMaxMessageSize();
				if (maxMessageSize > 0) {
					msgIn = new SizeLimitedInputStream(msgIn, maxMessageSize);
				}

				// Parse out the message headers
				MailHeaders headers = new MailHeaders(msgIn);
				headers = processMailHeaders(headers, ioSession, ctx);

				MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()), msgIn);

				System.out.println("Content--" + message.getContent());

				RSET.resetContext(ctx);
				sendResponse(ioSession, "250 Ok");
			} catch (MessagingException me) {
				RSET.resetContext(ctx);

				Exception e = me.getNextException();
				if (e != null && e instanceof MessageSizeException) {
					sendResponse(ioSession, "552 "
							+ DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SYSTEM_MSG_TOO_BIG)
							+ " Error processing message: " + e.getMessage());
				} else {
					sendResponse(ioSession, "451 "
							+ DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.UNDEFINED_STATUS)
							+ " Error processing message: " + me.getMessage());
				}
			}
		}
	}

	private MailHeaders processMailHeaders(MailHeaders headers, IoSession ioSession, SMTPContext ctx)
			throws MessagingException {

		SessionStatus sessionStatus = ctx.getSessionStatus();

		if (!headers.isSet(RFC2822Headers.DATE)) {
			headers.setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new Date()));
		}
		if (!headers.isSet(RFC2822Headers.FROM) && sessionStatus.getFrom() != null) {
			headers.setHeader(RFC2822Headers.FROM, sessionStatus.getFrom());
		}
		StringBuffer headerLineBuffer = new StringBuffer(512);
		// We will rebuild the header object to put our Received header at the
		// top
		Enumeration<?> headerLines = headers.getAllHeaderLines();
		MailHeaders newHeaders = new MailHeaders();
		// Put our Received header first
		headerLineBuffer.append(RFC2822Headers.RECEIVED + ": from ").append(ioSession.getRemoteAddress()).append(" ([")
				.append(ioSession.getRemoteAddress()).append("])");

		newHeaders.addHeaderLine(headerLineBuffer.toString());
		headerLineBuffer.delete(0, headerLineBuffer.length());

		headerLineBuffer.append("          by ").append(ctx.getSMTPServerConfig().getHostName()).append(" (").append(
				ctx.getSMTPServerConfig().getSystemName()).append(") with SMTP ID ").append(ioSession.getId());

		if (sessionStatus.getRecipientCount() == 1) {
			// Only indicate a recipient if they're the only recipient
			// (prevents email address harvesting and large headers in
			// bulk email)
			newHeaders.addHeaderLine(headerLineBuffer.toString());
			headerLineBuffer.delete(0, headerLineBuffer.length());
			headerLineBuffer.append("          for <").append(sessionStatus.getRecipients().iterator().next()).append(
					">;");
			newHeaders.addHeaderLine(headerLineBuffer.toString());
			headerLineBuffer.delete(0, headerLineBuffer.length());
		} else {
			// Put the ; on the end of the 'by' line
			headerLineBuffer.append(";");
			newHeaders.addHeaderLine(headerLineBuffer.toString());
			headerLineBuffer.delete(0, headerLineBuffer.length());
		}
		headerLineBuffer = null;
		newHeaders.addHeaderLine("          " + rfc822DateFormat.format(new Date()));

		// Add all the original message headers back in next
		while (headerLines.hasMoreElements()) {
			newHeaders.addHeaderLine((String) headerLines.nextElement());
		}
		return newHeaders;
	}

}
